#ifndef TOOLS_IMAGE_VIEWER_HPP
#define TOOLS_IMAGE_VIEWER_HPP

#include <opencv2/opencv.hpp>
#include <string>
#include <thread>
#include <mutex>
#include <map>
#include <memory>
#include <tuple>

// OpenGL 和 GLFW 头文件包含
// 使用 GLEW 加载 OpenGL 函数（系统已安装 GLEW）
#include <GL/glew.h>
// GLFW 必须在 GLEW 之后包含
#define GLFW_INCLUDE_NONE
#include <GLFW/glfw3.h>

namespace toolsLib
{

// 前向声明
class ImageViewerOpenGL;

// 前向声明
class ImageViewer;

// 窗口信息结构体：存储窗口实例和线程信息
struct WindowInfo
{
    std::unique_ptr<ImageViewerOpenGL> viewer;
    std::unique_ptr<std::thread>       thread;
    bool                               should_close;
    bool                               thread_finished;  // 线程是否已结束
    std::mutex                         mutex;
    ImageViewer*                       parent_viewer;     // 指向父 ImageViewer 实例
    std::string                        window_name;      // 窗口名称
    std::string                        bind_name;        // 绑定名称（空字符串表示非绑定窗口）
    cv::Size                           image_size;       // 图像尺寸（用于绑定窗口的尺寸检查）
};

// 公共接口类：提供简单的图像显示接口
class ImageViewer
{
    // 友元声明：允许 ImageViewerOpenGL 访问私有成员以进行同步
    friend class ImageViewerOpenGL;
    
  public:
    ImageViewer();
    ~ImageViewer();
    void showImage(const cv::Mat& image, const std::string& window_name);
    void closeWindow();
    void waitDisplay();  // 等待用户输入回车后继续
    void destroyDisplay(const std::string& window_name);  // 销毁指定窗口
    void destroyAllDisplay();  // 销毁所有窗口
    void removeWindow(const std::string& window_name);  // 从映射中移除窗口（线程安全，供回调使用）
    
    /**
     * @brief 设置指定窗口的像素边框颜色
     * @param window_name 窗口名称
     * @param x 像素X坐标
     * @param y 像素Y坐标
     * @param r 红色分量 (0.0-1.0)
     * @param g 绿色分量 (0.0-1.0)
     * @param b 蓝色分量 (0.0-1.0)
     */
    void setPixelBorderColor(const std::string& window_name, int x, int y, float r, float g, float b);
    
    /**
     * @brief 清除指定窗口的像素自定义边框颜色（恢复默认）
     * @param window_name 窗口名称
     * @param x 像素X坐标
     * @param y 像素Y坐标
     */
    void clearPixelBorderColor(const std::string& window_name, int x, int y);
    
    /**
     * @brief 清除指定窗口的所有自定义边框颜色（恢复默认）
     * @param window_name 窗口名称
     */
    void clearAllPixelBorderColors(const std::string& window_name);
    
    /**
     * @brief 设置指定窗口的默认边框颜色
     * @param window_name 窗口名称
     * @param r 红色分量 (0.0-1.0)
     * @param g 绿色分量 (0.0-1.0)
     * @param b 蓝色分量 (0.0-1.0)
     */
    void setDefaultBorderColor(const std::string& window_name, float r, float g, float b);
    
    /**
     * @brief 显示绑定图像窗口（相同 bind_name 的窗口会同步缩放和移动）
     * @param image 要显示的图像
     * @param window_name 窗口名称
     * @param bind_name 绑定名称，相同 bind_name 的窗口会同步操作
     */
    void showBindImage(const cv::Mat& image, const std::string& window_name, const std::string& bind_name);
    
    /**
     * @brief 销毁所有拥有相同 bind_name 的窗口
     * @param bind_name 绑定名称
     */
    void destroyBindImage(const std::string& bind_name);
    
    /**
     * @brief 设置指定窗口的位置（在显示窗口之前调用）
     * @param window_name 窗口名称
     * @param x 窗口X位置（像素，-1表示使用系统默认位置）
     * @param y 窗口Y位置（像素，-1表示使用系统默认位置）
     */
    void setWindowPosition(const std::string& window_name, int x, int y);

  private:
    std::map<std::string, std::unique_ptr<WindowInfo>> windows_;  // 窗口映射（window_name -> WindowInfo）
    std::map<std::string, std::vector<std::string>> bind_groups_;  // 绑定组映射（bind_name -> window_name列表）
    std::mutex                                         windows_mutex_;  // 保护窗口映射的互斥锁
    
    // 辅助函数：查找窗口（支持原始名称和带 " (bind)" 的名称）
    std::map<std::string, std::unique_ptr<WindowInfo>>::iterator findWindow(const std::string& window_name);
    
    static void runDisplayThread(WindowInfo* win_info, const cv::Mat& image, const std::string& window_name);  // 显示线程函数
    static void ensureGLFWInitialized();  // 确保 GLFW 在主线程中初始化
    static std::mutex glfw_init_mutex_;   // GLFW 初始化互斥锁
    static bool       glfw_initialized_;  // GLFW 是否已初始化
};

// 内部基于 OpenGL 的实现类：实际执行图像渲染和交互
class ImageViewerOpenGL
{
  public:
    ImageViewerOpenGL();
    ~ImageViewerOpenGL();
    void showImage(const cv::Mat& image, const std::string& window_name);
    void closeWindow();
    
    /**
     * @brief 设置指定像素的边框颜色
     * @param x 像素X坐标
     * @param y 像素Y坐标
     * @param r 红色分量 (0.0-1.0)
     * @param g 绿色分量 (0.0-1.0)
     * @param b 蓝色分量 (0.0-1.0)
     */
    void setPixelBorderColor(int x, int y, float r, float g, float b);
    
    /**
     * @brief 清除指定像素的自定义边框颜色（恢复默认）
     * @param x 像素X坐标
     * @param y 像素Y坐标
     */
    void clearPixelBorderColor(int x, int y);
    
    /**
     * @brief 清除所有自定义边框颜色（恢复默认）
     */
    void clearAllPixelBorderColors();
    
    /**
     * @brief 设置默认边框颜色
     * @param r 红色分量 (0.0-1.0)
     * @param g 绿色分量 (0.0-1.0)
     * @param b 蓝色分量 (0.0-1.0)
     */
    void setDefaultBorderColor(float r, float g, float b);
    
    /**
     * @brief 设置窗口位置
     * @param x 窗口X位置（像素，-1表示使用系统默认位置）
     * @param y 窗口Y位置（像素，-1表示使用系统默认位置）
     */
    void setWindowPosition(int x, int y);

  private:
    bool    initGLFW(const std::string& window_name, bool is_bind_window = false);
    bool    initGLResources();
    void    uploadTextureFromMat(const cv::Mat& mat);
    void    destroyGLResources();
    void    render();
    void    renderPixelValues();  // 在像素上显示 RGB 值
    void    renderPixelGrid();    // 绘制像素网格线
    void    initTextRenderer();   // 初始化文本渲染器
    void    initGridRenderer();   // 初始化网格渲染器
    void    getPixelBorderColor(int x, int y, float& r, float& g, float& b);  // 获取像素边框颜色
    void    drawTextAtScreenPos(float x, float y, const std::string& text, float scale = 1.0f, float r = 1.0f, float g = 1.0f, float b = 1.0f);
    cv::Mat createDigitTexture(char digit);  // 创建数字纹理

    // GLFW 回调函数：处理窗口事件
    static void framebufferSizeCallback(GLFWwindow* win, int w, int h);  // 窗口大小改变回调
    static void scrollCallback(GLFWwindow* win, double xoffset, double yoffset);  // 鼠标滚轮回调
    static void mouseButtonCallback(GLFWwindow* win, int button, int action, int mods);  // 鼠标按键回调
    static void cursorPosCallback(GLFWwindow* win, double xpos, double ypos);  // 鼠标移动回调
    static void windowCloseCallback(GLFWwindow* win);  // 窗口关闭回调
    
    // 绑定窗口同步函数
    void syncViewStateToBindGroup();  // 将当前视图状态同步到绑定组中的其他窗口
    void syncViewStateFromOther(double zoom, double offset_x, double offset_y);  // 从其他窗口同步视图状态

    // 辅助函数：从 GLFWwindow 获取 this 指针
    void                      attachToWindow();  // 将 this 指针附加到窗口
    static ImageViewerOpenGL* getThis(GLFWwindow* win);  // 从窗口获取实例指针

    // 窗口和上下文
    GLFWwindow* window_ = nullptr;  // GLFW 窗口句柄
    std::string window_name_;       // 窗口名称

  public:
    WindowInfo* window_info_ = nullptr;  // 指向窗口信息的指针（用于关闭回调，需要公开访问）

    // 图像数据
    cv::Mat original_image_;  // 原始图像数据

    // 视图状态：控制图像的显示位置和缩放
    int    win_w_    = 800;      // 窗口宽度（像素）
    int    win_h_    = 600;      // 窗口高度（像素）
    int    win_x_    = -1;       // 窗口X位置（像素，-1表示使用系统默认位置）
    int    win_y_    = -1;       // 窗口Y位置（像素，-1表示使用系统默认位置）
    double zoom_     = 1.0;      // 缩放因子（1.0 = 1图像像素对应1屏幕像素）
    double offset_x_ = 0.0;      // 图像X轴偏移量（图像坐标）
    double offset_y_ = 0.0;      // 图像Y轴偏移量（图像坐标）
    
    // 绑定窗口相关
    std::string bind_name_;     // 绑定名称（空字符串表示非绑定窗口）
    bool is_syncing_ = false;   // 是否正在同步（避免递归同步）

    // 鼠标状态：跟踪拖拽操作
    bool   dragging_     = false;  // 是否正在拖拽
    double last_mouse_x_ = 0.0;    // 上次鼠标X坐标
    double last_mouse_y_ = 0.0;    // 上次鼠标Y坐标

    // 主着色器程序：用于渲染图像
    GLuint program_ = 0;   // 着色器程序ID
    GLuint vao_     = 0;   // 顶点数组对象ID
    GLuint vbo_     = 0;   // 顶点缓冲区对象ID
    GLuint texture_ = 0;   // 纹理对象ID

    // 文本渲染：用于在像素上显示RGB值
    GLuint text_program_       = 0;   // 文本渲染着色器程序ID
    GLuint text_vao_           = 0;   // 文本渲染顶点数组对象ID
    GLuint text_vbo_           = 0;   // 文本渲染顶点缓冲区对象ID
    GLuint digit_textures_[10] = {0}; // 0-9 数字纹理数组
    double min_zoom_for_text_  = 60.0; // 当缩放大于这个值时显示文本

    // 网格渲染：用于绘制像素边界线
    GLuint grid_program_      = 0;   // 网格渲染着色器程序ID
    GLuint grid_vao_          = 0;   // 网格渲染顶点数组对象ID
    GLuint grid_vbo_          = 0;   // 网格渲染顶点缓冲区对象ID
    double min_zoom_for_grid_ = 5.0; // 当缩放大于这个值时显示网格
    
    // 像素边框颜色：存储每个像素的自定义边框颜色
    // key: (y * image_width + x), value: (r, g, b)
    std::map<int, std::tuple<float, float, float>> pixel_border_colors_;
    std::mutex pixel_border_colors_mutex_;  // 保护像素边框颜色的互斥锁
    float default_border_color_[3] = {243.0f / 255.0f, 234.0f / 255.0f, 176.0f / 255.0f};  // 默认边框颜色
};

// 着色器源代码声明：在 .cpp 文件中定义
extern const char* vertex_shader_src;    // 顶点着色器源代码
extern const char* fragment_shader_src;  // 片段着色器源代码

}  // namespace toolsLib

#endif  // TOOLS_IMAGE_VIEWER_HPP
